#include "tetgenParser.h"

using namespace std;
using namespace MeshUtils;


bool MeshUtils::TetgenParser::parseNode(std::ifstream& source, unsigned int& idx, double& x, double& y, double& z)
{
	Lexeme lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER)
		throw ParserException("Failed to read point index");
	idx = lex.integer;

	lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER and lex.type != REAL)
		throw ParserException("Failed to read x coord");
	if(lex.type == INTEGER)
		x = (double) lex.integer;
	else
		x = (double) lex.real;

	lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER and lex.type != REAL)
		throw ParserException("Failed to read y coord");
	if(lex.type == INTEGER)
		y = (double) lex.integer;
	else
		y = lex.real;

	lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER and lex.type != REAL)
		throw ParserException("Failed to read z coord");
	if(lex.type == INTEGER)
		z = (double) lex.integer;
	else
		z = (double) lex.real;

	lex = ParserHelper::lexer(source);
	if(lex.type != EOL)
		throw ParserException("Failed to read eol");

	return true;
}

bool MeshUtils::TetgenParser::parseElement(std::ifstream& source, unsigned int& idx, vector<unsigned int>& nodesList)
{
	Lexeme lex = ParserHelper::lexer(source);
	idx = lex.integer;

	for(unsigned int i = 0 ; i < 4 ; i++)
	{
		lex = ParserHelper::lexer(source);
		if(lex.type != INTEGER)
			throw ParserException("Failed to read elm : invalid number of nodes in nodesList");
		nodesList.push_back(gmshToInternal[lex.integer]);
	}

	lex = ParserHelper::lexer(source);
	if(lex.type != EOL)
		throw ParserException("Failed to eol");

	return true;
}

void MeshUtils::TetgenParser::load(std::vector<MeshUtils::Vector3>& nodes, std::vector<MeshUtils::Element>& elements,  unsigned int& nbNodes, unsigned int& nbElts)
{
	std::ifstream infile(filename);

	try {
		Lexeme lex = ParserHelper::lexer(infile);
		while(lex.type == COMMENT)
		{
			cout << lex.alpha << endl;
			lex = ParserHelper::lexer(infile);

		}

		if(lex.type != INTEGER)
			throw ParserException("Bad tetgen format : failed to read nodes number");

		nbNodes = lex.integer;

		lex = ParserHelper::lexer(infile); //node order
		if(lex.type != INTEGER)
			throw ParserException("Bad tetgen format : failed to read nodes order");

		lex = ParserHelper::lexer(infile); //?
		if(lex.type != INTEGER)
			throw ParserException("Bad tetgen format : failed to read param 3");


		lex = ParserHelper::lexer(infile); //?
		if(lex.type != INTEGER)
			throw ParserException("Bad tetgen format : failed to read nodes param 4");

		lex = ParserHelper::lexer(infile); //Flush EOL

		//Parse nodes
		MeshUtils::Vector3 node;
		for(unsigned int i = 0 ; i < nbNodes ; i++)
		{
			parseNode(infile, i, node.x, node.y, node.z);
			MeshUtils::Vector3 nodeCopy = node;
			unsigned int internalIdx = nodes.size();
			nodes.push_back(nodeCopy);
			gmshToInternal[i] = internalIdx;
		}
		lex = ParserHelper::lexer(infile);
		while(lex.type == COMMENT)//Flush comment
			lex = ParserHelper::lexer(infile);


		if(lex.type != INTEGER)
			throw ParserException("Bad tetgen format : failed to read elmt number");
		nbElts = lex.integer;

		lex = ParserHelper::lexer(infile);
		if(lex.type != INTEGER)
			throw ParserException("Bad tetgen format : failed to read elmt type");


		lex = ParserHelper::lexer(infile);
		if(lex.type != INTEGER)
			throw ParserException("Bad tetgen format : failed to read elmt param 3");


		lex = ParserHelper::lexer(infile); //Flush EOL


		//Parse elts
		for(unsigned int i = 0 ; i < nbElts ; i++)
		{
			MeshUtils::Element elt;
			parseElement(infile, elt.idx, elt.nodesList);
			elements.push_back(elt);
		}

		std::cout << "end parse elements : " << nbElts << " elts (counted) " << endl;

	} catch(ParserException e)
	{
		infile.close();
		std::cout << e.what() << std::endl;
		//exit(0);
	}

	infile.close();
	return;
}

Mesh TetgenParser::load()
{
	vector<MeshUtils::Vector3> nodes;
	std::vector<MeshUtils::Element> elts;
	unsigned int nbNodes, nbElts;

	this->load(nodes, elts, nbNodes, nbElts);

	MeshUtils::Mesh mesh;
	mesh.nodes = nodes;
	mesh.elts = elts;

	vector<MeshUtils::Vector3> nodesB;

	mesh.computeBoundary();

	return mesh;
}


/*
Mesh TetgenParser::loadBoundary()
{
	vector<MeshUtils::Vector3> nodes;
	std::vector<MeshUtils::Element> elts;
	unsigned int nbNodes, nbElts;

	this->load(nodes, elts, nbNodes, nbElts);

	MeshUtils::Mesh mesh;
	mesh.nodes = nodes;

	std::vector<Triangle> triangles;
	std::map<unsigned long long int, unsigned int> faceCommon;

	for(std::vector<MeshUtils::Element>::iterator eIt = elts.begin() ; eIt != elts.end() ; eIt++)
	{
		short int a = eIt->nodesList[0];
		short int b = eIt->nodesList[1];
		short int c = eIt->nodesList[2];
		short int d = eIt->nodesList[3];


		faceKey f1; f1.a = b; f1.b = c; f1.c =d;
		faceKey f2; f2.a = a; f2.b = d; f2.c =c;
		faceKey f3; f3.a = a; f3.b = b; f3.c =d;
		faceKey f4; f4.a = a; f4.b = c; f4.c =b;

		faceCommon[f1.key] += 1;
		faceCommon[f2.key] += 1;
		faceCommon[f3.key] += 1;
		faceCommon[f4.key] += 1;
	}

	map<unsigned int, unsigned int> nodesMap;
	for(std::map<unsigned long long int, unsigned int>::iterator it = faceCommon.begin() ; it != faceCommon.end() ; it++)
	{
		if(it->second == 1 or true)
		{
			faceKey k;
			k.key = it->first;

			if(!nodesMap[k.a])
			{
				nodesMap[k.a] = mesh.faceNodes.size()+1;
				mesh.faceNodes.push_back(nodes[k.a]);
			}
			if(!nodesMap[k.b])
			{
				nodesMap[k.b] = mesh.faceNodes.size()+1;
				mesh.faceNodes.push_back(nodes[k.b]);
			}
			if(!nodesMap[k.c])
			{
				nodesMap[k.c] = mesh.faceNodes.size()+1;
				mesh.faceNodes.push_back(nodes[k.c]);
			}


			Face_t f;
			f.A = nodesMap[k.a]-1;
			f.B = nodesMap[k.b]-1;
			f.C = nodesMap[k.c]-1;


			mesh.faces.push_back(f);
			cout << "find a boundary face !" << k.a << " " << k.b << " " << k.c << endl;
			cout << "find a boundary face !" << f.A << " " << f.B << " " << f.C << endl;
		}
	}

	mesh.triangles = triangles;
	return mesh;
}
*/
